
#include "gpx_parser_util.h"

#include <fstream>
#include "glog/logging.h"
#include "date_time.h"
#include "expat_parser.h"
#include "gps_parser_util.h"
#include "gps.pb.h"

namespace gps_proto {

// static
bool GpsParser::ParseFromString(const std::string& gpx, GpsProto* gps_proto) {
  GpxParser gpx_parser(gps_proto);
  return ExpatParser::ParseString(gpx, &gpx_parser, NULL, false);
}

// static
bool GpxParser::ParseFromIstream(std::istream* input, GpsProto* gps_proto) {

  if (!input || !gps_proto) {
    return false;  // No input or no output?  Not much to do.
  }
  // Create a GpxParser instance which will write to the user's gps_proto.
  GpxParser gpx_parser(gps_proto);
  // Create an ExpatParser using the (non-namespace-aware) ExpatHandler for GPX.
  ExpatParser expat_parser(&gpx_parser, false);
  // Use the ExpatParser's streamed parsing API on the input.
  // (This loop is taken from libkml's src/kml/engine/kml_stream.cc)
  const size_t kBufSize(4096);
  while (input->good()) {
    // Ask expat for a buffer to write into.
    void* buf = expat_parser.GetInternalBuffer(kBufSize);
    if (!buf) {
      return false;  // Memory allocation error.
    }
    // Read a buffer's worth from the input stream.
    std::streamsize read_size =
        input->read(static_cast<char*>(buf), kBufSize).gcount();
    // Parse that buffer.
    if (!expat_parser.ParseInternalBuffer(read_size, NULL, input->eof())) {
      return false;  // Parse error.
    }
  }
  return true;
}

// static
bool GpxParser::ParseFromFile(const char* filename, GpsProto* gps_proto) {
  std::ifstream input_gpx(filename,
                          std::ios_base::in|std::ios_base::binary);
  if (!input_gpx.is_open() || !input_gpx.good()) {
    LOG(ERROR) << "open failed: " << filename;
    return false;
  }
  return ParseFromIstream(&input_gpx, gps_proto);
}

}
